---
title: Menubar
description: A menu that stays visible on the screen, often seen in desktop apps, offering easy access to a standard set of commands.
---

{/* prettier-ignore-start */}
{/* prettier-ignore-end */}

import Code from '@/components/Code.astro';
import { LinkButton } from '@/components/react/LinkButton';
import { Aside, Tabs, TabItem } from '@astrojs/starlight/components';
import importedCode from '@rnr/reusables/components/ui/menubar?raw';

<LinkButton href='https://rn-primitives.vercel.app/menubar'>Menubar Primitive</LinkButton>
<LinkButton href='/components/text'>Text Component</LinkButton>
<LinkButton target='_blank' href='https://rnr-showcase.vercel.app/menubar'>
  Demo
</LinkButton>

<br />

A menu that stays visible on the screen, often seen in desktop apps, offering easy access to a standard set of commands.

### Installation

<Tabs>
  <TabItem label='CLI'> 
    ```bash
    npx @react-native-reusables/cli@latest add menubar
    ```
  </TabItem>
  <TabItem label='Manual'>
    <Aside type='tip' title='Dependencies'>
      Before copy/pasting, add the <a href='https://rn-primitives.vercel.app/menubar' className='text-white font-bold'> menubar primitive</a> and the <a href='/components/text' className='text-white font-bold'>text component</a> to your project.
    </Aside>

    <br />

    **Copy/paste the following code to `~/components/ui/menubar.tsx`:**

    <Code code={importedCode} lang='tsx' title='~/components/ui/menubar.tsx' />
  </TabItem>
</Tabs>

### Usage

<Aside type="caution">

  Requires a `<PortalHost />` as the last child of your `<Root/>` (`app/_layout.tsx`) component

  ```tsx
  import { PortalHost } from '@rn-primitives/portal';

  function Root() {
    return (
      <>
        <Stack />
        {/* Default Portal Host (one per app) */}
        <PortalHost />
      </>
    );
  }
  ```

</Aside>

```tsx
import { useNavigation } from 'expo-router';
import * as React from 'react';
import { Pressable, StyleSheet, View } from 'react-native';
import Animated, { FadeIn } from 'react-native-reanimated';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import {
  Menubar,
  MenubarCheckboxItem,
  MenubarContent,
  MenubarItem,
  MenubarMenu,
  MenubarRadioGroup,
  MenubarRadioItem,
  MenubarSeparator,
  MenubarShortcut,
  MenubarSub,
  MenubarSubContent,
  MenubarSubTrigger,
  MenubarTrigger,
} from '~/components/ui/menubar';
import { Text } from '~/components/ui/text';

function Example() {
  const insets = useSafeAreaInsets();
  const contentInsets = {
    top: insets.top,
    bottom: insets.bottom,
    left: 12,
    right: 12,
  };
  const [value, setValue] = React.useState<string | undefined>();
  const [isSubOpen, setIsSubOpen] = React.useState(false);
  const [isSubOpen2, setIsSubOpen2] = React.useState(false);
  const [isChecked, setIsChecked] = React.useState(false);
  const [isChecked2, setIsChecked2] = React.useState(false);
  const [radio, setRadio] = React.useState('michael');
  const navigation = useNavigation();
  React.useEffect(() => {
    const sub = navigation.addListener('blur', () => {
      onValueChange(undefined);
    });

    return sub;
  }, []);

  function closeSubs() {
    setIsSubOpen(false);
    setIsSubOpen2(false);
  }

  function onValueChange(val: string | undefined) {
    if (typeof val === 'string') {
      setValue(val);
      return;
    }
    closeSubs();
    setValue(undefined);
  }

  return (
    <View className='flex-1 items-center p-4'>
      {!!value && (
        <Pressable
          onPress={() => {
            onValueChange(undefined);
          }}
          style={StyleSheet.absoluteFill}
        />
      )}
      <Menubar value={value} onValueChange={onValueChange}>
        <MenubarMenu value='file'>
          <MenubarTrigger onPress={closeSubs}>
            <Text>File</Text>
          </MenubarTrigger>
          <MenubarContent insets={contentInsets}>
            <MenubarItem>
              <Text>New Tab</Text>
              <MenubarShortcut>⌘T</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <Text>New Window</Text>
              <MenubarShortcut>⌘N</MenubarShortcut>
            </MenubarItem>
            <MenubarItem disabled>
              <Text>New Incognito Window</Text>
            </MenubarItem>
            <MenubarSeparator />
            <MenubarSub open={isSubOpen} onOpenChange={setIsSubOpen}>
              <MenubarSubTrigger>
                <Text>Share</Text>
              </MenubarSubTrigger>
              <MenubarSubContent>
                <Animated.View entering={FadeIn.duration(200)}>
                  <MenubarItem>
                    <Text>Email link</Text>
                  </MenubarItem>
                  <MenubarItem>
                    <Text>Messages</Text>
                  </MenubarItem>
                  <MenubarItem>
                    <Text>Notes</Text>
                  </MenubarItem>
                </Animated.View>
              </MenubarSubContent>
            </MenubarSub>
            <MenubarSeparator />
            <MenubarItem>
              <Text>Print...</Text>
              <MenubarShortcut>⌘P</MenubarShortcut>
            </MenubarItem>
          </MenubarContent>
        </MenubarMenu>
        <MenubarMenu value='edit'>
          <MenubarTrigger onPress={closeSubs}>
            <Text>Edit</Text>
          </MenubarTrigger>
          <MenubarContent insets={contentInsets} className='native:w-48'>
            <MenubarItem>
              <Text>Undo</Text>
              <MenubarShortcut>⌘Z</MenubarShortcut>
            </MenubarItem>
            <MenubarItem>
              <Text>Redo</Text>
              <MenubarShortcut>⇧⌘Z</MenubarShortcut>
            </MenubarItem>
            <MenubarSeparator />
            <MenubarSub open={isSubOpen2} onOpenChange={setIsSubOpen2}>
              <MenubarSubTrigger>
                <Text>Find</Text>
              </MenubarSubTrigger>
              <MenubarSubContent>
                <Animated.View entering={FadeIn.duration(200)}>
                  <MenubarItem>
                    <Text>Search the web</Text>
                  </MenubarItem>
                  <MenubarSeparator />
                  <MenubarItem>
                    <Text>Find...</Text>
                  </MenubarItem>
                  <MenubarItem>
                    <Text>Find Next</Text>
                  </MenubarItem>
                  <MenubarItem>
                    <Text>Find Previous</Text>
                  </MenubarItem>
                </Animated.View>
              </MenubarSubContent>
            </MenubarSub>
            <MenubarSeparator />
            <MenubarItem>
              <Text>Cut</Text>
            </MenubarItem>
            <MenubarItem>
              <Text>Copy</Text>
            </MenubarItem>
            <MenubarItem>
              <Text>Paste</Text>
            </MenubarItem>
          </MenubarContent>
        </MenubarMenu>
        <MenubarMenu value='view'>
          <MenubarTrigger onPress={closeSubs}>
            <Text>View</Text>
          </MenubarTrigger>
          <MenubarContent insets={contentInsets}>
            <MenubarCheckboxItem
              checked={isChecked}
              onCheckedChange={setIsChecked}
              closeOnPress={false}
            >
              <Text>Always Show Bookmarks Bar</Text>
            </MenubarCheckboxItem>
            <MenubarCheckboxItem
              checked={isChecked2}
              onCheckedChange={setIsChecked2}
              closeOnPress={false}
            >
              <Text>Always Show Full URLs</Text>
            </MenubarCheckboxItem>
            <MenubarSeparator />
            <MenubarItem inset>
              <Text>Reload</Text>
              <MenubarShortcut>⌘R</MenubarShortcut>
            </MenubarItem>
            <MenubarItem disabled inset>
              <Text>Force Reload</Text>
              <MenubarShortcut>⇧⌘R</MenubarShortcut>
            </MenubarItem>
            <MenubarSeparator />
            <MenubarItem inset>
              <Text>Toggle Fullscreen</Text>
            </MenubarItem>
            <MenubarSeparator />
            <MenubarItem inset>
              <Text>Hide Sidebar</Text>
            </MenubarItem>
          </MenubarContent>
        </MenubarMenu>
        <MenubarMenu value='profile'>
          <MenubarTrigger onPress={closeSubs}>
            <Text>Profiles</Text>
          </MenubarTrigger>
          <MenubarContent insets={contentInsets}>
            <MenubarRadioGroup value={radio} onValueChange={setRadio}>
              <MenubarRadioItem closeOnPress={false} value='andy'>
                <Text>Andy</Text>
              </MenubarRadioItem>
              <MenubarRadioItem closeOnPress={false} value='michael'>
                <Text>Michael</Text>
              </MenubarRadioItem>
              <MenubarRadioItem closeOnPress={false} value='creed'>
                <Text>Creed</Text>
              </MenubarRadioItem>
            </MenubarRadioGroup>
            <MenubarSeparator />
            <MenubarItem inset>
              <Text>Edit...</Text>
            </MenubarItem>
            <MenubarSeparator />
            <MenubarItem inset>
              <Text>Add Profile...</Text>
            </MenubarItem>
          </MenubarContent>
        </MenubarMenu>
      </Menubar>
    </View>
  );
}
```

## Props

### Menubar

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |     Note     |
| :----------: | :----------------------: | :----------: |
|     open*    |         boolean          |                         |
| onOpenChange*| (value: boolean) => void |                         |
|   asChild    |         boolean          |       _(optional)_      |

### MenubarMenu

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |     Note     |
| :----------: | :----------------------: | :----------: |
|     value*    |         string          |                         |
|   asChild    |         boolean          |       _(optional)_      |

### MenubarTrigger

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
|  inset  | boolean | _(optional)_ |

### MenubarPortal

|    Prop    |               Type               |         Note          |
| :--------: | :------------------------------: | :-------------------: |
| children\* |         React.ReactNode          |                       |
| forceMount |        true \| undefined         |     _(optional)_      |
|  hostName  |              string              | Web Only _(optional)_ |
| container  | HTMLElement \| null \| undefined | Web Only _(optional)_ |

### MenubarContent

Extends [`View`](https://reactnative.dev/docs/view#props) props

|          Prop           |                     Type                     |           Note           |
| :---------------------: | :------------------------------------------: | :----------------------: |
|         asChild         |                   boolean                    |       _(optional)_       |
|      overlayStyle       |            StyleProp\<ViewStyle>             |       _(optional)_       |
|    overlayClassName     |                    string                    |       _(optional)_       |
|       forceMount        |              true \| undefined               |       _(optional)_       |
|       alignOffset       |                    number                    |       _(optional)_       |
|         insets          |                    Insets                    |       _(optional)_       |
|     avoidCollisions     |                   boolean                    |       _(optional)_       |
|          align          |         'start' \| 'center' \| 'end'         |       _(optional)_       |
|          side           |              'top' \| 'bottom'               |       _(optional)_       |
|       sideOffset        |                    number                    |       _(optional)_       |
| disablePositioningStyle |                   boolean                    | Native Only _(optional)_ |
|          loop           |                   boolean                    |  Web Only _(optional)_   |
|    onCloseAutoFocus     |            (event: Event) => void            |  Web Only _(optional)_   |
|     onEscapeKeyDown     |        (event: KeyboardEvent) => void        |  Web Only _(optional)_   |
|  onPointerDownOutside   |  (event\: PointerDownOutsideEvent) => void   |  Web Only _(optional)_   |
|     onFocusOutside      |      (event: FocusOutsideEvent) => void      |  Web Only _(optional)_   |
|    onInteractOutside    | PointerDownOutsideEvent \| FocusOutsideEvent |  Web Only _(optional)_   |
|    collisionBoundary    |  Element \| null \| Array\<Element \| null>  |  Web Only _(optional)_   |
|         sticky          |            'partial' \| 'always'             |  Web Only _(optional)_   |
|    hideWhenDetached     |                   boolean                    |  Web Only _(optional)_   |

### MenubarGroup

Extends [`Text`](https://reactnative.dev/docs/text#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |

### MenubarLabel

Extends [`Text`](https://reactnative.dev/docs/text#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |

### MenubarItem

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
| textValue | boolean | _(optional)_ |
| closeOnPress | boolean | _(optional)_ |

### MenubarCheckboxItem

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|     Prop     |           Type           |           Note          |
| :----------: | :----------------------: | :---------------------: |
|   checked*   |         boolean          |                         |
|onCheckedChange*| (value: boolean) => void |                       |
|   textValue* |         string           |                         |
|  asChild     |         boolean          |       _(optional)_      |
| closeOnPress |         boolean          | Native Only_(optional)_ |

### MenubarRadioGroup

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |           Note          |
| :----------: | :----------------------: | :---------------------: |
|   value*   |         boolean          |                         |
|onValueChange*| (value: boolean) => void |                         |
|  asChild     |         boolean          |       _(optional)_      |

### MenubarRadioItem

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|     Prop     |           Type           |           Note          |
| :----------: | :----------------------: | :---------------------: |
|   value*     |         boolean          |                         |
|onCheckedChange*| (value: boolean) => void |                       |
|  asChild     |         boolean          |       _(optional)_      |
| closeOnPress |         boolean          | Native Only_(optional)_ |

### MenubarSeparator

Extends [`View`](https://reactnative.dev/docs/view#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
| decorative | boolean | _(optional)_ |

### MenubarSub

Extends [`View`](https://reactnative.dev/docs/view#props) props

|     Prop     |           Type           |     Note     |
| :----------: | :----------------------: | :----------: |
|   asChild    |         boolean          | _(optional)_ |
| defaultOpen  |         boolean          | _(optional)_ |
|     open     |         boolean          | _(optional)_ |
| onOpenChange | (value: boolean) => void | _(optional)_ |

### MenubarSubTrigger

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| textValue | string | _(optional)_ |
| asChild | boolean | _(optional)_ |

### MenubarSubContent

Extends [`Pressable`](https://reactnative.dev/docs/pressable#props) props

|  Prop   |  Type   |     Note     |
| :-----: | :-----: | :----------: |
| asChild | boolean | _(optional)_ |
| forceMount | true /| undefined | _(optional)_ |

### MenubarShortcut

Extends [`Text`](https://reactnative.dev/docs/text#props) props